package com.oglvip.business.remote.support.proxy.exchange;

import com.oglvip.business.remote.support.exception.RestException;
import com.oglvip.business.remote.support.proxy.ProxyFactory;
import com.oglvip.business.remote.support.request.RequestEntity;
import com.oglvip.business.remote.support.utils.MethodUtils;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.Map;

/**
 * @auther hanchao
 * @date 2016/12/3 14:49
 */
public class RestTemplateExchanger implements Exchanger {
    private RestTemplate restTemplate;

    public RestTemplateExchanger(RestTemplate restTemplate){
        this.restTemplate = restTemplate;
    }

    @Override
    public Object request(RequestEntity requestEntity, Method method) throws Throwable {
        //get respone type
        ResponseEntity result = null;
        if(method.getGenericReturnType() instanceof ParameterizedType){
            ParameterizedTypeReference typeReference = (ParameterizedTypeReference) ProxyFactory.getSpringRefrence(MethodUtils.getGenericReturnTypeName(method));
            if(typeReference == null){
                throw new RestException("cant get generic reference from proxy factory!");
            }
            result = restTemplate.exchange(requestEntity.toUrl(), buildMethod(requestEntity), buildEntity(requestEntity), typeReference);
        }else{
            result = restTemplate.exchange(requestEntity.toUrl(), buildMethod(requestEntity), buildEntity(requestEntity), method.getReturnType());
        }
        return result.getBody();
    }

    protected HttpMethod buildMethod(RequestEntity requestEntity){
        switch (requestEntity.getHttpMethod()){
            case RequestEntity.GET:
                return HttpMethod.GET;
            case RequestEntity.POST:
                return HttpMethod.POST;
            case RequestEntity.PUT:
                return HttpMethod.PUT;
            case RequestEntity.DELETE:
                return HttpMethod.DELETE;
            default:
                return HttpMethod.GET;
        }
    }

    protected HttpEntity buildEntity(RequestEntity requestEntity){
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType(requestEntity.getContentType());
        headers.setContentType(type);
        headers.add("Accept", requestEntity.getAccept());
        HttpEntity entity;
        if(requestEntity.getFormParams() != null && !requestEntity.getFormParams().isEmpty()){
            entity = new HttpEntity<Map<String,Object>>(requestEntity.getFormParams(),headers);
        }else if(requestEntity.getBody() != null){
            entity = new HttpEntity<Object>(requestEntity.getBody(),headers);
        }else{
            entity = new HttpEntity(headers);
        }
        return entity;
    }
}
